Chapter 9
Polymorphic Return Types

Stefan Schirra ([email protected])

For some geometric operations, the type of the result of the operation is not fixed a priori, but depends on the input. Intersection computation is a prime example. The standard object-oriented approach to this is defining a common base class for all possible result types and returning a reference or a pointer to an object of the result type by a reference or pointer to the base class. Then all the virtual member functions in the interface of the base class can be applied to the result object and the implementation corresponding to the actual result type is called. It is hard to define approriate base class interface functions (besides draw()).

Cgal has chosen a different approach, since Cgal wants to avoid large class hierarchies. With the Cgal class Object , you can fake a common base class , see Figure 9.1.

Figure 9.1:  UML class diagram for faked object hierarchies (since 2.2-I-4).

Faked object heirarchies UML diagram

Functions having a polymorphic return type create an object of the actual result type and wrap it into an object of type Object. You can use the make_object() function to do this.

template <class R>
Object
intersection(const Plane_3<R>& plane1, const Plane_3<R>& plane2);
The following piece of code is taken from the above Cgal intersection routine:
    if (det != zero) 
    {
        is_pt = Point_3<R>(zero, c*s-d*r, d*q-b*s, det);
        is_dir = Direction_3<R>(det, c*p-a*r, a*q-b*p);
        return make_object(Line_3<R>(is_pt, is_dir));
    }

There is only one member operation defined for Object, a test for an empty object. In order to make use of the returned object, you can try to assign it to the possible return types using CGAL::object_cast function; see also the definition of the class Object in the Cgal kernel manual.

For functions potentially computing more than one polymorphic objects, some Cgal functions use std::list<CGAL::Object> as return value.

std::list<CGAL::Object>
fct_might_return_several_objects_of_different_types(...);

A more generic approach is the use of OutputIterators, just like the STL does:

template <typename OutputIterator>
OutputIterator
fct_might_return_several_objects_of_different_types(..., OutputIterator result);
where iterator_traits<OutputIterator>::value_type must be Object. The sequence of objects returned starts with the output iterator passed to the function. The output iterator returned is the past-the-end iterator of the constructed sequence of objects.